---
title: "AQS源码笔记"
categories:
- java
- concurrent
tags:
---

<div id="content">
<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#org8b1c6f4">Inner Class Node</a></li>
<li><a href="#org7c431cb">Inner Class ConditionObject</a></li>
<li><a href="#orge006176">CAS方法</a>
<ul>
<li><a href="#org8c2538c">boolean compareAndSetHead(Node update)</a></li>
<li><a href="#org62a154e">boolean compareAndSetTail(Node expect, Node update)</a></li>
<li><a href="#orgd5ca796">boolean compareAndSetSetWaitStatus(Node node, int expect, int update)</a></li>
<li><a href="#org655402a">boolean compareAndSetNext(Node node, Node expect, Node update)</a></li>
</ul>
</li>
<li><a href="#org5009f52">锁方法</a>
<ul>
<li><a href="#orge353032">void acquire(long arg)</a>
<ul>
<li><a href="#orge878ca5">boolean tryAcquire(long arg)</a></li>
<li><a href="#org8e748bb">Node addWaiter(Node mode)</a></li>
<li><a href="#org4970edd">boolean acquireQueued(final Node node, long arg)</a></li>
</ul>
</li>
<li><a href="#org57d5223">boolean release(long arg)</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="outline-2" id="outline-container-org8b1c6f4">
<h2 id="org8b1c6f4">Inner Class Node</h2>
<div class="outline-text-2" id="text-org8b1c6f4">
<p>
表示双向链表中的单个结点。主要的字段：
</p>
<ul class="org-ul">
<li>前后结点的指针（数据结构 - 链表）</li>
<li>thread 字段，线程进入等待队列时，被包装成Node，这个字段就是那个线程。</li>
<li>waitStatus 字段表示一个线程是否应该阻塞。AQS中实现的等待队列是CLH的变体，一个结点上的线程的相关控制信息被保存在它的前继结点上。当结点的前继结点释放的时候，这个结点被通知，
<ul class="org-ul">
<li>SIGNAL 当前结点的后结点是（或者即将）阻塞，所以当前线程在释放或者取消时，需要唤醒下个结点。</li>
<li>CANCELLED 当前结点由于超时或中断，面被取消。</li>
<li>CONDITION 当前结点正位于条件队列中，</li>
<li>PROPAGATE</li>
<li>0 其他，不是以上所有状态</li>
</ul></li>
<li>nextWaiter 链接到下个条件等待的结点</li>
</ul>
</div>
</div>
<div class="outline-2" id="outline-container-org7c431cb">
<h2 id="org7c431cb">Inner Class ConditionObject</h2>
</div>
<div class="outline-2" id="outline-container-orge006176">
<h2 id="orge006176">CAS方法</h2>
<div class="outline-text-2" id="text-orge006176">
<p>
这个类中用到了Unsafe类的CAS方法进行并发控制。
</p>
</div>
<div class="outline-3" id="outline-container-org8c2538c">
<h3 id="org8c2538c">boolean compareAndSetHead(Node update)</h3>
<div class="outline-text-3" id="text-org8c2538c">
<p>
如果链表是空，则设置链表头，代码如下：
</p>
<div class="org-src-container">
<pre class="src src-java">Unsafe.compareAndSwapObject(<span style="font-weight: bold;">this</span>, <span style="font-weight: bold; text-decoration: underline;">headOffset</span>, <span style="font-weight: bold; text-decoration: underline;">null</span>, <span style="font-weight: bold; text-decoration: underline;">update</span>);
</pre>
</div>
<p>
前两个参数，用于定位要比较的数据。this表示数据在当前对象中，headOffset是类的静态变量，在类的static块中被初始化值。
headOffset的意思是：成员变量head相对于类的内存地址偏移（大概就这个意思吧）。
第三个参数，是期望的值，第四个参数是新值。
所以这个方法的意思是：比较对象成员变量head是否为空，如果是则修改为update。如果比较失败，则返回失败。
</p>
</div>
</div>
<div class="outline-3" id="outline-container-org62a154e">
<h3 id="org62a154e">boolean compareAndSetTail(Node expect, Node update)</h3>
<div class="outline-text-3" id="text-org62a154e">
<p>
同上。注意第一个参数是期望的当前值。
</p>
</div>
</div>
<div class="outline-3" id="outline-container-orgd5ca796">
<h3 id="orgd5ca796">boolean compareAndSetSetWaitStatus(Node node, int expect, int update)</h3>
<div class="outline-text-3" id="text-orgd5ca796">
<p>
比较然后设置Node对象中waitStatus的值。
</p>
</div>
</div>
<div class="outline-3" id="outline-container-org655402a">
<h3 id="org655402a">boolean compareAndSetNext(Node node, Node expect, Node update)</h3>
<div class="outline-text-3" id="text-org655402a">
<p>
比较然后设置Node对象中next变量的值。
</p>
</div>
</div>
</div>
<div class="outline-2" id="outline-container-org5009f52">
<h2 id="org5009f52">锁方法</h2>
<div class="outline-text-2" id="text-org5009f52">
</div>
<div class="outline-3" id="outline-container-orge353032">
<h3 id="orge353032">void acquire(long arg)</h3>
<div class="outline-text-3" id="text-orge353032">
<p>
这是加锁的方法，方法的代码如下：
</p>
<div class="org-src-container">
<pre class="src src-java"><span style="font-weight: bold;">if</span>(!tryAcquire(arg) &amp;&amp;
   acquireQueued(addWaiter(<span style="font-weight: bold; text-decoration: underline;">Node</span>.EXCLUSIVE), arg)) {
    selfInterrupt();
}
</pre>
</div>
<p>
这个方法以独占模式获取锁，无视中断。这个方法首先调用 {% raw %} tryAcquire {% endraw %} 方法，如果成功则直接返回。失败则入队列等待。
</p>
</div>
<div class="outline-4" id="outline-container-orge878ca5">
<h4 id="orge878ca5">boolean tryAcquire(long arg)</h4>
<div class="outline-text-4" id="text-orge878ca5">
<p>
这个方法需要由子类去实现
</p>
</div>
</div>
<div class="outline-4" id="outline-container-org8e748bb">
<h4 id="org8e748bb">Node addWaiter(Node mode)</h4>
<div class="outline-text-4" id="text-org8e748bb">
<p>
如果 {% raw %} tryAcquire {% endraw %} 失败，则调用这个方法。这个方法将当前线程包装到Node结点中，然后通过CAS方法，将结点入队列。
</p>
</div>
</div>
<div class="outline-4" id="outline-container-org4970edd">
<h4 id="org4970edd">boolean acquireQueued(final Node node, long arg)</h4>
<div class="outline-text-4" id="text-org4970edd">
<p>
调用了addWaiter之后，这个方法被调用。方法中使用一个循环，（TODO 进行队列等待？）
</p>
<p>
方法内又调用了下面的方法。
</p>
</div>
<ul class="org-ul">
<li><a id="org20617e8"></a>boolean shouldParkAfterFailedAcquire(Node pred, Node node)<br/>
<div class="outline-text-5" id="text-org20617e8">
<p>
对失败获取锁的结点进行检查并更新状态。如果线程应当阻塞，则返回true。参数pred是node的前结点（两个参数的值有要求，需要pred = node.pred）
这个方法的主要流程如下：
</p>
<pre class="example">
if pred.waitStatus is SIGNAL:
    return true
if pred.waitStatus &gt; 0: # 已取消的状态
    则从队列中移除pred，然后再向前找结点，直到找到不是取消的。
else: # 其他状态
    通过CAS方法将其设置为SIGNAL。
return false
</pre>
</div>
</li>
<li><a id="org21db5ea"></a>boolean parkAndCheckInterrupt()<br/>
<div class="outline-text-5" id="text-org21db5ea">
<p>
禁用当前线程，然后返回它是否被中断了。
</p>
</div>
</li>
</ul>
</div>
</div>
<div class="outline-3" id="outline-container-org57d5223">
<h3 id="org57d5223">boolean release(long arg)</h3>
<div class="outline-text-3" id="text-org57d5223">
<p>
这是解锁的方法，方法的代码如下：
</p>
<div class="org-src-container">
<pre class="src src-java"><span style="font-weight: bold;">if</span> (tryRelease(arg)) {
    <span style="font-weight: bold; text-decoration: underline;">Node</span> <span style="font-weight: bold; font-style: italic;">h</span> = head;
    <span style="font-weight: bold;">if</span> (h != <span style="font-weight: bold; text-decoration: underline;">null</span> &amp;&amp; h.waitStatus != 0) 
        unparkSuccessor(h);
    <span style="font-weight: bold;">return</span> <span style="font-weight: bold; text-decoration: underline;">true</span>;
}
<span style="font-weight: bold;">return</span> <span style="font-weight: bold; text-decoration: underline;">false</span>;
</pre>
</div>
<p>
首先调用 {% raw %} tryRelease {% endraw %} 方法，这个方法由子类实现。如果 {% raw %} tryRelease {% endraw %} 成功，则解锁链表中的下个结点。
解锁就是调用Unsafe.unpark方法，激活node结点中保存的线程。
</p>
</div>
</div>
</div>
</div>
<div class="status" id="postamble">
<p class="author">Author: gdme1320</p>
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
